import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class mainTest {


        static ArrayList<Process> ready=new ArrayList();//就绪队列
        static ArrayList<Process> block=new ArrayList();//阻塞队列
        static Scanner sc=new Scanner(System.in);

        public static void main(String[] args) {
            menu();
        }
        public static void menu() {
            while (true) {
                System.out.println("********************");
                System.out.println("*      系统主菜单    *");
                System.out.println("********************");
                System.out.println("*       1…创建      *");
                System.out.println("*       2…阻塞      *");
                System.out.println("*       3…唤醒      *");
                System.out.println("*       4…终止      *");
                System.out.println("*       5…显示      *");
                System.out.println("*       6…调度      *");
                System.out.println("*       0…退出      *");
                System.out.println("********************");
                System.out.println("请输入您需要的功能:(0-5):");
                int x = sc.nextInt();
                if (x == 0) {
                    break;
                }
                if (x == 1) {
                    add();
                }
                if (x == 2) {
                    block();
                }
                if (x == 3) {
                    huanxing();
                }
                if (x == 4) {
                    delete();
                }
                if (x == 5) {
                    xianshi();
                }
                if (x == 6){
                    diaodu();
                }
                if(x<0||x>6){
                    System.out.println("输入失败！请输入1-6之间的数字！");
                }
            }
        }
        //x==1 创建进程
        public static void add(){
            Process jc = new Process();
            System.out.println("进程名：");
            jc.setName(sc.next());
            System.out.println("到达时间：");
            jc.setArriveTime(sc.nextInt());
            System.out.println("优先级");
            jc.setPriority(sc.nextInt());
            System.out.println("运行时间");
            jc.setWorkTime(sc.nextInt());
            int p=0;
            if (ready.size()!=0){
                for (int i = 0; i < ready.size(); i++) {
                    if (ready.get(i).getName().equals(jc.getName())) {
                        System.out.println("就绪队列中存在同名进程，无法添加！");
                        p++;
                        break;
                    }
                }
            }
            if(p==0) {
                if (block.size() != 0) {
                    for (int i = 0; i < block.size(); i++) {
                        if (block.get(i).getName().equals(jc.getName())) {
                            System.out.println("阻塞队列中存在同名进程，无法添加！");
                            p++;
                            break;
                        }
                    }
                }
            }
            if(p==0){
                ready.add(jc);
                System.out.println("添加进程成功！");
                ready.get(ready.size()-1).setState("就绪");
            }
        }
        //x==2 阻塞进程
        public static void block(){
            int p=0;
            System.out.println("请输入要阻塞的进程名：");
            String cha=sc.next();
            if(ready.size()<=0){
                System.out.println("就绪队列为空,请先添加进程！");
            }
            else {
                for (int j = 0; j < block.size(); j++) {
                    if (block.get(j).getName().equals(cha)) {
                        System.out.println("该进程已处在阻塞状态");//因为该进程在阻塞队列中
                        p++;
                        break;
                    }
                }
                if(p==0) {
                    for (int i = 0; i < ready.size(); i++) {
                        if (ready.get(i).getName().equals(cha)) {
                            block.add(ready.get(i));
                            ready.get(i).setState("阻塞");
                            ready.remove(i);
                            System.out.println("进程已阻塞");
                            p++;
                            break;
                        }
                    }
                }
                if (p==0) {
                    System.out.println("队列中没有该进程！无法阻塞！");//阻塞队列和就绪队列中都没有该进程
                }
            }
        }
        //x==3 唤醒进程
        public static void huanxing(){
            System.out.println("请输入要唤醒的进程：");
            String huan=sc.next();
            if(block.size()==0){
                System.out.println("阻塞队列为空！无法唤醒！");
            }
            else {
                for (int i = 0; i < block.size(); i++) {
                    if (block.get(i).getName().equals(huan)) {
                        block.get(i).setState("就绪");
                        ready.add(block.get(i));
                        block.remove(i);
                        System.out.println("进程已唤醒");
                        break;
                    }
                    if(i==block.size()-1 ){
                        System.out.println("阻塞队列中没有该进程！无法唤醒！");
                    }
                }
            }
        }
        //x==4 终止进程
        public static void delete(){
            System.out.println("请输入要终止的进程：");
            String zhong=sc.next();
            if(block.size()==0&&ready.size()==0){
                System.out.println("就绪队列和阻塞队列为空,请先添加进程！");
            }
            int p=0;
            for (int i = 0; i < block.size(); i++) {//遍历阻塞队列，如果有，就删除该进程
                if (block.get(i).getName().equals(zhong) ) {
                    block.remove(i);
                    p++;
                    break;
                }
            }
            if(p==0) {
                for (int i = 0; i < ready.size(); i++) {//遍历就绪队列，如果有，就删除该进程
                    if (ready.get(i).getName().equals(zhong)) {
                        ready.remove(i);
                        p++;
                        break;
                    }
                }
            }
            if(p==1){System.out.println("进程已终止");}
            else {System.out.println("该进程不存在，无法终止！");}//阻塞队列和就绪队列都没有该进程

        }
        //x==5 显示进程
        public static void xianshi(){
            System.out.println("就绪队列：");
            for(int i = 0; i < ready.size(); i++){//遍历就绪队列
                if(i!=ready.size()-1) {//当该进程不是队列最后一个 他的指针就指向下一个进程
                    ready.get(i).setPointer(ready.get(i + 1).getName());
                    System.out.println(ready.get(i));
                }
                if(i==ready.size()-1&&ready.size()-1>=0){//当该进程是队列最后一个 他的指针就指向NULL
                    ready.get(i).setPointer("NULL");
                    System.out.println(ready.get(i));
                }
            }
            System.out.println("阻塞队列：");
            for(int j = 0; j < block.size(); j++){//遍历阻塞队列
                if(j!=block.size()-1){//当该进程不是队列最后一个 他的指针就指向下一个进程
                    block.get(j).setPointer(block.get(j+1).getName());
                    System.out.println(block.get(j));
                }
                if(j==block.size()-1&&block.size()-1>=0){//当该进程是队列最后一个 他的指针就指向NULL
                    block.get(j).setPointer("NULL");
                    System.out.println(block.get(j));
                }
            }
        }
        //x==6  调度算法
        public static void diaodu() {
            System.out.println("*********************");
            System.out.println("*   进程调度子菜单    *");
            System.out.println("*********************");
            System.out.println("*  0…返回子菜单      *");
            System.out.println("*  1…先来先服务调度   *");
            System.out.println("*  2…短作业优先级调度 *");
            System.out.println("请选择您需要的功能选项: ");
            System.out.println("*********************");
            Scanner sc=new Scanner(System.in);
            while(true) {
                ArrayList<Dispatch> forkArr=new ArrayList<Dispatch>();
                for (int i = 0; i < ready.size(); i++) {

                    forkArr.add(new Dispatch(ready.get(i).getNum(),ready.get(i).getName(),ready.get(i).getWorkTime(),ready.get(i).getWorkTime(),ready.get(i).getPriority()));
                }

                switch (sc.nextInt()) {
                    case 1:
                        System.out.println("先来先服务算法");
                        ArrayList<Dispatch> FSFCArr=FCFS(forkArr);
                        printArr(FSFCArr);
                        break;
                    case 2:
                        System.out.println("短作业优先算法");
                        ArrayList<Dispatch> SJFArr=SJF(forkArr);
                        printArr(SJFArr);
                        break;
                    case 0:
                        menu();
                        break;
                }
            }
        }



        //1. 先到先服务算法
        public static ArrayList<Dispatch> FCFS(ArrayList<Dispatch> forkArr)
        {

            Dispatch nowFork;
            ArrayList<Dispatch> workArr=new ArrayList<Dispatch>();
            nowFork=forkArr.get(0);
            //第一个进入工作队列中1

            forkArr.remove(nowFork);
            workArr.add(nowFork);
            workArr.get(0).setStartTime(nowFork.getArriveTime());
            workArr.get(0).setOverTime(nowFork.getArriveTime()+nowFork.getWorkTime());

            //根据先到先服务原则将输入队列排序并放入工作队列中
            for(int i=0;i<forkArr.size();i++)
            {
                for(int j=i+1;j<forkArr.size();j++)
                {
                    if(forkArr.get(i).getArriveTime()>forkArr.get(j).getArriveTime())
                    {
                        Collections.swap(forkArr, j, i);
                    }
                }
            }

            for(Dispatch fc : forkArr)
            {
                fc.setStartTime(workArr.get(workArr.size()-1).getOverTime());
                fc.setOverTime(fc.getStartTime()+fc.getWorkTime());
                workArr.add(fc);

            }
            return workArr;
        }

        //2. 短作业优先算法
        public static ArrayList<Dispatch> SJF(ArrayList<Dispatch> PCBArr) {
            //根据到达时间获取第一个到达并且服务时间较短的进程
            Dispatch first;
            first = PCBArr.get(0);
            for(int i=0;i<PCBArr.size();i++) {
                if(first.getArriveTime() == PCBArr.get(i).getArriveTime()) {
                    if(first.getWorkTime() > PCBArr.get(i).getWorkTime()) {
                        first = PCBArr.get(i);
                    }
                } else if(first.getArriveTime() > PCBArr.get(i).getArriveTime()) {
                    first = PCBArr.get(i);
                }
            }

            ArrayList<Dispatch> tempArr = new ArrayList<Dispatch>();
            for (int i=0;i<PCBArr.size();i++) {
                tempArr.add(PCBArr.get(i));
            }
            //第一个进入工作队列中
            ArrayList<Dispatch> workArr = new ArrayList<Dispatch>();  //存储结果数组
            workArr.add(first);
            workArr.get(0).setStartTime(first.getArriveTime());
            workArr.get(0).setOverTime(first.getArriveTime()+first.getWorkTime());

            //删除已经进入工作队列的第一个进程的PCB
            tempArr.remove(first);

            //剩下的进程通过最短进程优先调度算法依次进入工作队列
            while(!tempArr.isEmpty()) {
                ArrayList<Dispatch> ret = new ArrayList<Dispatch>();
                double lastFinshTime = workArr.get(workArr.size()-1).getOverTime();

                //筛选出在上一个进程结束前到达的进程放入ret数组
                for(Dispatch p : tempArr) {
                    if(p.getArriveTime() < lastFinshTime) {
                        ret.add(p);
                    }
                }

                if(ret.isEmpty()){
                    for(Dispatch p : tempArr) {
                        ret.add(p);
                    }
                }

                //筛选出ret数组中最短的进程first2
                Dispatch first2;
                first2 = ret.get(0);
                for(int i=0;i<ret.size();i++) {
                    if(first2.getWorkTime() > ret.get(i).getWorkTime()) {
                        first2 = ret.get(i);
                    }
                }

                //将first2对应进程放入工作队列并运行，同时在临时复制的PCB（retArr)中删除该进程的PCB
                first2.setStartTime(lastFinshTime);
                first2.setOverTime(first2.getStartTime()+first2.getWorkTime());
                workArr.add(first2);
                tempArr.remove(first2);
            }
            return workArr;
        }

        //输出算法
        public static void printArr(ArrayList<Dispatch> forkArr)
        {

            System.out.println("=============================");
            System.out.println("进程名  到达时间  运行时间  优先级  开始运行时间  运行结束时间 ");
            for(Dispatch fc : forkArr)
            {
                System.out.print("\t"+fc.getName());
                System.out.print("\t "+fc.getArriveTime());
                System.out.print("\t  "+fc.getWorkTime());
                System.out.print("\t   "+fc.getPriority());
                System.out.print("\t    "+fc.getStartTime());
                System.out.println("\t\t  "+fc.getOverTime());
            }
        }

    }